package dao

import (
	"context"
	"encoding/json"
	"fmt"
	"gbox-one-machine/models"
	"net/http"
)

// http path
const (
	algosPath          = "/api/v1/resource_center/camera_algo"
	cleanAlgosPath     = "/api/v1/resource_center/camera_algo/clean"
	subAlgosPath       = "/api/v1/resource_center/camera_algo?wait=true&timeout=15&id=%s"
	cameraAlgosPath    = "/api/v1/resource_center/camera/%s/algo"
	setCameraAlgosPath = "/api/v1/resource_center/camera/%s/algo"
	delCameraAlgosPath = "/api/v1/resource_center/camera/%s/algo"
)

type algosResp struct {
	ReturnCode   int                   `json:"returnCode"`
	ErrorMessage string                `json:"errorMessage"`
	Result       []*models.CameraAlgos `json:"result"`
}

// GetCamerasAlgos get all cameras algos
func (d *Dao) GetCamerasAlgos(ctx context.Context) ([]*models.CameraAlgos, error) {

	resResp := new(algosResp)

	resp, err := d.http().R().SetContext(ctx).Get(d.resCenterHost + algosPath)
	if err != nil {
		return nil, fmt.Errorf("HTTP request err: %s", err)
	}

	if resp.StatusCode() != http.StatusOK {
		return nil, fmt.Errorf("HTTP status %s", resp.Status())
	}

	if err := json.Unmarshal(resp.Body(), resResp); err != nil {
		return nil, err
	}

	if resResp.ReturnCode != 0 {
		return nil, fmt.Errorf("Errcode: %d, Msg: %s", resResp.ReturnCode, resResp.ErrorMessage)
	}

	return resResp.Result, nil
}

// WatchCamerasAlgos watch algos
func (d *Dao) WatchCamerasAlgos(ctx context.Context, id string, cb func(algos []*models.CameraAlgos) error) error {
	if id == "" {
		return fmt.Errorf("ID is empty")
	}
	url := d.resCenterHost + fmt.Sprintf(subAlgosPath, id)

	if err := d.SubLongPoll(ctx, url, func(data []byte) error {

		resResp := new(algosResp)
		if err := json.Unmarshal(data, resResp); err != nil {
			return fmt.Errorf("Resp decode err: %s body: %s", err, data)
		}

		if err := cb(resResp.Result); err != nil {
			return err
		}
		return nil
	}); err != nil {
		return err
	}

	return nil
}

type cameraAlgosResp struct {
	ReturnCode   int                 `json:"returnCode"`
	ErrorMessage string              `json:"errorMessage"`
	Result       *models.CameraAlgos `json:"result"`
}

// GetCameraAlgos get camera algos
func (d *Dao) GetCameraAlgos(ctx context.Context, id string) (*models.CameraAlgos, error) {

	if id == "" {
		return nil, fmt.Errorf("ID empty")
	}
	resResp := new(cameraAlgosResp)

	resp, err := d.http().R().SetContext(ctx).Get(fmt.Sprintf(d.resCenterHost+cameraAlgosPath, id))
	if err != nil {
		return nil, fmt.Errorf("HTTP request err: %s", err)
	}

	if resp.StatusCode() != http.StatusOK {
		return nil, fmt.Errorf("HTTP status %s", resp.Status())
	}

	if err := json.Unmarshal(resp.Body(), resResp); err != nil {
		return nil, err
	}

	if resResp.ReturnCode != 0 {
		return nil, fmt.Errorf("Errcode: %d, Msg: %s", resResp.ReturnCode, resResp.ErrorMessage)
	}

	return resResp.Result, nil
}

type setCameraAlgosResp struct {
	ReturnCode   int         `json:"returnCode"`
	ErrorMessage string      `json:"errorMessage"`
	Result       interface{} `json:"result"`
}

// SetCameraAlgos set camera algos
func (d *Dao) SetCameraAlgos(ctx context.Context, id string, camerasAlgos *models.CameraAlgos) error {
	if id == "" {
		return fmt.Errorf("ID empty")
	}

	resResp := new(setCameraAlgosResp)

	resp, err := d.http().R().SetContext(ctx).SetBody(camerasAlgos.Algos).Put(fmt.Sprintf(d.resCenterHost+setCameraAlgosPath, id))
	if err != nil {
		return fmt.Errorf("HTTP request err: %s", err)
	}

	if resp.StatusCode() != http.StatusOK {
		return fmt.Errorf("HTTP status %s", resp.Status())
	}

	if err := json.Unmarshal(resp.Body(), resResp); err != nil {
		return err
	}

	if resResp.ReturnCode != 0 {
		return fmt.Errorf("Errcode: %d, Msg: %s", resResp.ReturnCode, resResp.ErrorMessage)
	}

	return nil
}

type delCameraAlgosResp struct {
	ReturnCode   int         `json:"returnCode"`
	ErrorMessage string      `json:"errorMessage"`
	Result       interface{} `json:"result"`
}

// DeleteCameraAlgos delete camera algos
func (d *Dao) DeleteCameraAlgos(ctx context.Context, id string) error {

	if id == "" {
		return fmt.Errorf("ID empty")
	}

	resResp := new(delCameraAlgosResp)

	resp, err := d.http().R().SetContext(ctx).Delete(fmt.Sprintf(d.resCenterHost+delCameraAlgosPath, id))
	if err != nil {
		return fmt.Errorf("HTTP request err: %s", err)
	}

	if resp.StatusCode() != http.StatusOK {
		return fmt.Errorf("HTTP status %s", resp.Status())
	}

	if err := json.Unmarshal(resp.Body(), resResp); err != nil {
		return err
	}

	if resResp.ReturnCode != 0 {
		return fmt.Errorf("Errcode: %d, Msg: %s", resResp.ReturnCode, resResp.ErrorMessage)
	}

	return nil
}

type cleanAlgosResp struct {
	ReturnCode   int         `json:"returnCode"`
	ErrorMessage string      `json:"errorMessage"`
	Result       interface{} `json:"result"`
}

// CleanAlgos clean Algos
func (d *Dao) CleanAlgos(ctx context.Context) error {

	resResp := new(cleanAlgosResp)

	resp, err := d.http().R().SetContext(ctx).Post(d.resCenterHost + cleanAlgosPath)
	if err != nil {
		return fmt.Errorf("HTTP request err: %s", err)
	}

	if resp.StatusCode() != http.StatusOK {
		return fmt.Errorf("HTTP status %s", resp.Status())
	}

	if err := json.Unmarshal(resp.Body(), resResp); err != nil {
		return err
	}

	if resResp.ReturnCode != 0 {
		return fmt.Errorf("Errcode: %d, Msg: %s", resResp.ReturnCode, resResp.ErrorMessage)
	}

	return nil
}
